home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Extensions / Imaging / PIL / FpxImagePlugin.py < prev    next >
Encoding:
Text File  |  2000-06-23  |  5.0 KB  |  225 lines

  1. #
  2. # THIS IS WORK IN PROGRESS
  3. #
  4. # The Python Imaging Library.
  5. # $Id: FpxImagePlugin.py,v 1.1.1.2 1999/01/13 09:39:44 sjoerd Exp $
  6. #
  7. # FlashPix support for PIL
  8. #
  9. # History:
  10. # 97-01-25 fl    Created (reads uncompressed RGB images only)
  11. #
  12. # Copyright (c) Secret Labs AB 1997.
  13. # Copyright (c) Fredrik Lundh 1997.
  14. #
  15. # See the README file for information on usage and redistribution.
  16. #
  17.  
  18.  
  19. __version__ = "0.1"
  20.  
  21.  
  22. import string
  23.  
  24. import Image, ImageFile
  25. from OleFileIO import *
  26.  
  27.  
  28. # we map from colour field tuples to (mode, rawmode) descriptors
  29. MODES = {
  30.     # opacity
  31.     (0x00007ffe): ("A", "L"),
  32.     # monochrome
  33.     (0x00010000,): ("L", "L"),
  34.     (0x00018000, 0x00017ffe): ("RGBA", "LA"),
  35.     # photo YCC
  36.     (0x00020000, 0x00020001, 0x00020002): ("RGB", "YCC;P"),
  37.     (0x00028000, 0x00028001, 0x00028002, 0x00027ffe): ("RGBA", "YCCA;P"),
  38.     # standard RGB (NIFRGB)
  39.     (0x00030000, 0x00030001, 0x00030002): ("RGB","RGB"),
  40.     (0x00038000, 0x00038001, 0x00038002, 0x00037ffe): ("RGBA","RGBA"),
  41. }
  42.  
  43. #
  44. # --------------------------------------------------------------------
  45.  
  46. def _accept(prefix):
  47.     return prefix[:8] == MAGIC
  48.  
  49.  
  50. class FpxImageFile(ImageFile.ImageFile):
  51.  
  52.     format = "FPX"
  53.     format_description = "FlashPix"
  54.  
  55.     def _open(self):
  56.     #
  57.     # read the OLE directory and see if this is a likely
  58.     # to be a FlashPix file
  59.  
  60.     try:
  61.         self.ole = OleFileIO(self.fp)
  62.     except IOError:
  63.         raise SyntaxError, "not an FPX file; invalid OLE file"
  64.  
  65.     if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B":
  66.         raise SyntaxError, "not an FPX file; bad root CLSID"
  67.  
  68.     self._open_index(1)
  69.  
  70.     def _open_index(self, index = 1):
  71.     #
  72.     # get the Image Contents Property Set
  73.  
  74.     prop = self.ole.getproperties([
  75.         "Data Object Store %06d" % index,
  76.         "\005Image Contents"
  77.     ])
  78.  
  79.     # size (highest resolution)
  80.  
  81.     self.size = prop[0x1000002], prop[0x1000003]
  82.  
  83.     size = max(self.size)
  84.     i = 1
  85.     while size > 64:
  86.         size = size / 2
  87.         i = i + 1
  88.     self.maxid = i - 1
  89.  
  90.     # mode.  instead of using a single field for this, flashpix
  91.     # requires you to specify the mode for each channel in each
  92.     # resolution subimage, and leaves it to the decoder to make
  93.     # sure that they all match.  for now, we'll cheat and assume
  94.     # that this is always the case.
  95.  
  96.     id = self.maxid << 16
  97.  
  98.     s = prop[0x2000002|id]
  99.  
  100.     colors = []
  101.     for i in range(i32(s, 4)):
  102.         # note: for now, we ignore the "uncalibrated" flag
  103.         colors.append(i32(s, 8+i*4) & 0x7fffffff)
  104.  
  105.     self.mode, self.rawmode = MODES[tuple(colors)]
  106.  
  107.     # load JPEG tables, if any
  108.     self.jpeg = {}
  109.     for i in range(256):
  110.         id = 0x3000001|(i << 16)
  111.         if prop.has_key(id):
  112.         self.jpeg[i] = prop[id]
  113.  
  114.     # print len(self.jpeg), "tables loaded"
  115.  
  116.     self._open_subimage(1, self.maxid)
  117.  
  118.     def _open_subimage(self, index = 1, subimage = 0):
  119.     #
  120.     # setup tile descriptors for a given subimage
  121.  
  122.     stream = [
  123.         "Data Object Store %06d" % index,
  124.         "Resolution %04d" % subimage,
  125.         "Subimage 0000 Header"
  126.     ]
  127.  
  128.     fp = self.ole.openstream(stream)
  129.  
  130.     # skip prefix
  131.     p = fp.read(28)
  132.  
  133.     # header stream
  134.     s = fp.read(36)
  135.  
  136.     size = i32(s, 4), i32(s, 8)
  137.     tilecount = i32(s, 12)
  138.     tilesize = i32(s, 16), i32(s, 20)
  139.     channels = i32(s, 24)
  140.     offset = i32(s, 28)
  141.     length = i32(s, 32)
  142.  
  143.     # print size, self.mode, self.rawmode
  144.  
  145.     if size != self.size:
  146.         raise IOError, "subimage mismatch"
  147.         
  148.     # get tile descriptors
  149.     fp.seek(28 + offset)
  150.     s = fp.read(i32(s, 12) * length)
  151.  
  152.     x = y = 0
  153.     xsize, ysize = size
  154.     xtile, ytile = tilesize
  155.     self.tile = []
  156.  
  157.     for i in range(0, len(s), length):
  158.  
  159.         compression = i32(s, i+8)
  160.  
  161.         if compression == 0:
  162.         self.tile.append(("raw", (x,y,x+xtile,y+ytile),
  163.             i32(s, i) + 28, (self.rawmode)))
  164.  
  165.         elif compression == 1:
  166.  
  167.         # FIXME: the fill decoder is not implemented
  168.         self.tile.append(("fill", (x,y,x+xtile,y+ytile),
  169.             i32(s, i) + 28, (self.rawmode, s[12:16])))
  170.  
  171.         elif compression == 2:
  172.  
  173.         internal_color_conversion = ord(s[14])
  174.         jpeg_tables = ord(s[15])
  175.         rawmode = self.rawmode
  176.  
  177.         if internal_color_conversion:
  178.             # The image is stored as usual (usually YCbCr).
  179.             if rawmode == "RGBA":
  180.             # For "RGBA", data is stored as YCbCrA based on
  181.             # negative RGB. The following trick works around
  182.             # this problem :
  183.             jpegmode, rawmode = "YCbCrK", "CMYK"
  184.             else:
  185.             jpegmode = None # let the decoder decide
  186.  
  187.         else:
  188.             # The image is stored as defined by rawmode
  189.             jpegmode = rawmode
  190.  
  191.         self.tile.append(("jpeg", (x,y,x+xtile,y+ytile),
  192.             i32(s, i) + 28, (rawmode, jpegmode)))
  193.  
  194.         # FIXME: jpeg tables are tile dependent; the prefix
  195.         # data must be placed in the tile descriptor itself!
  196.  
  197.         if jpeg_tables:
  198.             self.tile_prefix = self.jpeg[jpeg_tables]
  199.  
  200.         else:
  201.         raise IOError, "unknown/invalid compression"
  202.  
  203.         x = x + xtile
  204.         if x >= xsize:
  205.         x, y = 0, y + ytile
  206.         if y >= ysize:
  207.             break # isn't really required
  208.  
  209.     self.stream = stream
  210.     self.fp = None
  211.  
  212.     def load(self, modify=0):
  213.  
  214.     if not self.fp:
  215.         self.fp = self.ole.openstream(self.stream[:2] + ["Subimage 0000 Data"])
  216.  
  217.     ImageFile.ImageFile.load(self, modify)
  218.  
  219. #
  220. # --------------------------------------------------------------------
  221.  
  222. Image.register_open("FPX", FpxImageFile, _accept)
  223.  
  224. Image.register_extension("FPX", ".fpx")
  225.